﻿/////////////////////////////////////////////////////////////////////////
//
// This module provides sample code used to demonstrate the use
// of the KinectAudioSource for speech recognition
//
// Copyright © Microsoft Corporation.  All rights reserved.  
// This code is licensed under the terms of the 
// Microsoft Kinect for Windows SDK (Beta) from Microsoft Research 
// License Agreement: http://research.microsoft.com/KinectSDK-ToU
//
/////////////////////////////////////////////////////////////////////////

/*
 * IMPORTANT: This sample requires the following components to be installed:
 * 
 * Speech Platform Runtime (v10.2) x86. Even on x64 platforms the x86 needs to be used because the MSR Kinect SDK runtime is x86
 * http://www.microsoft.com/downloads/en/details.aspx?FamilyID=bb0f72cb-b86b-46d1-bf06-665895a313c7
 * 
 * Kinect English Language Pack: MSKinectLangPack_enUS.msi (available in the same location as the Kinect For
 * Windows SDK)
 *
 * Speech Platform SDK (v10.2) 
 * http://www.microsoft.com/downloads/en/details.aspx?FamilyID=1b1604d3-4f66-4241-9a21-90a294a5c9a4&displaylang=en
 * */

using System;
using System.IO;
using System.Linq;
using Microsoft.Research.Kinect.Audio;
using Microsoft.Speech.AudioFormat;
using Microsoft.Speech.Recognition;
using System.Diagnostics;

namespace KinnectInput
{
    public class VideoSpeechControl : IDisposable
    {
        private const string RecognizerId = "SR_MS_en-US_Kinect_10.0";

        KinectAudioSource source;
        SpeechRecognitionEngine sre;

        public event EventHandler PlayTold;
        public event EventHandler StopTold;
        Stream s;
        public bool recognizing { get; set; }
        bool kinectTold;

        public VideoSpeechControl()
        {
            recognizing = false;
            source = new KinectAudioSource();
            source.FeatureMode = true;
            source.AutomaticGainControl = false; //Important to turn this off for speech recognition
            source.SystemMode = SystemMode.OptibeamArrayOnly; //No AEC for this sample

            RecognizerInfo ri = SpeechRecognitionEngine.InstalledRecognizers().Where(r => r.Id == RecognizerId).FirstOrDefault();

            if (ri == null)
            {
                Debug.WriteLine("Could not find speech recognizer: {0}. Please refer to the sample requirements.", RecognizerId);
                return;
            }

            Debug.WriteLine("Using: {0}", ri.Name);

            sre = new SpeechRecognitionEngine(ri.Id);
            {
                var choices = new Choices();
                choices.Add("kinect play");
                choices.Add("kinect stop");

                var gb = new GrammarBuilder();
                //Specify the culture to match the recognizer in case we are running in a different culture.                                 
                gb.Culture = ri.Culture;
                gb.Append(choices);


                // Create the actual Grammar instance, and then load it into the speech recognizer.
                var g = new Grammar(gb);

                sre.LoadGrammar(g);
                sre.SpeechRecognized += SreSpeechRecognized;
                //sre.SpeechHypothesized += SreSpeechHypothesized;
                sre.SpeechRecognitionRejected += SreSpeechRecognitionRejected;

                s = source.Start();
                sre.SetInputToAudioStream(s,
                                          new SpeechAudioFormatInfo(
                                              EncodingFormat.Pcm, 16000, 16, 1,
                                              32000, 2, null));
            }
        }

        

        public void Start()
        {
            if (!recognizing)
            {
                sre.RecognizeAsync(RecognizeMode.Multiple);
                recognizing = true;
            }
        }

        public void Stop()
        {
            if (sre != null)
            {
                if (recognizing)
                {
                    sre.RecognizeAsyncStop();
                    recognizing = false;
                }
            }
        }

        void SreSpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
        {
            kinectTold = false;
            //Console.WriteLine("\nSpeech Rejected");
            //if (e.Result != null)
            //    DumpRecordedAudio(e.Result.Audio);
        }

        //void SreSpeechHypothesized(object sender, SpeechHypothesizedEventArgs e)
        //{
        //    //Console.Write("\rSpeech Hypothesized: \t{0}", e.Result.Text);
        //}

        public event EventHandler SpeechRecognized;

        void SreSpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            //This first release of the Kinect language pack doesn't have a reliable confidence model, so 
            //we don't use e.Result.Confidence here.
            //if (e.Result.Text == "kinect")
            //{ 
            //    kinectTold = true;
            //    if (!KinectXNATools.MediaEvalulator.isPlaying(JupiterLibrary.Jupiter.soundPing.State))
            //    {
            //        JupiterLibrary.Jupiter.soundPing.Play();
            //    }
            //}
            //else if (kinectTold)
            //{

            if (e.Result.Text == "kinect play" && this.PlayTold != null)
            {
                this.PlayTold(this, e);

            }
            else if (e.Result.Text == "kinect stop" && this.StopTold != null)
            {

                this.StopTold(this, e);
            }
            if (SpeechRecognized != null)
                SpeechRecognized(this, e);
           // }
        }

        //private static void DumpRecordedAudio(RecognizedAudio audio)
        //{
        //    if (audio == null) return;

        //    int fileId = 0;
        //    string filename;
        //    while (File.Exists((filename = "RetainedAudio_" + fileId + ".wav")))
        //        fileId++;

        //    Console.WriteLine("\nWriting file: {0}", filename);
        //    using (var file = new FileStream(filename, System.IO.FileMode.CreateNew))
        //        audio.WriteToWaveStream(file);
        //}


        public void Dispose()
        {

            try
            {
                if (source != null)
                    source.Dispose();
            }
            finally
            {
                try
                {
                    if (sre != null)
                        sre.Dispose();
                }
                finally
                {
                    if (s != null)
                        s.Dispose();
                }
            }
        }
    }
}
